package server.main;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.StringTokenizer;

import net.sourceforge.jsdp.Bandwith;
import net.sourceforge.jsdp.Media;
import net.sourceforge.jsdp.MediaDescription;
import net.sourceforge.jsdp.SDPException;
import net.sourceforge.jsdp.SDPFactory;
import net.sourceforge.jsdp.SessionDescription;
import net.sourceforge.jsdp.TimeDescription;
import server.rtp.RtpSender;
import android.util.Log;

public class RtspServer extends Thread
{
	//RTP variables:
	//----------------
	RtpSender rs = null;

	InetAddress ClientIPAddr; //Client IP address
	int RTP_dest_port = 0; //destination port for RTP packets  (given by the RTSP Client)

	//RTSP variables
	//----------------
	//rtsp states
	private final static int READY = 0;
	private final static int PLAYING = 1;
	private final static int PAUSING = 2;
	//rtsp message types
	private final static int OPTIONS = 3;
	private final static int DESCRIBE = 4;
	private final static int SETUP = 5;
	private final static int PLAY = 6;
	private final static int PAUSE = 7;
	private final static int TEARDOWN = 8;

	private  static int state; //RTSP Server state == INIT or READY or PLAY
	private Socket RTSPSocket; //socket used to send/receive RTSP messages
	//input and output stream filters
	private BufferedReader RTSPBufferedReader;
	private BufferedWriter RTSPBufferedWriter;
	private int RTSP_ID = 0; //ID of the RTSP session
	private int RTSPSeqNb = 0; //Sequence number of RTSP messages within the session
	private boolean isRunning = true;
	private InputStream videoIn = null;
	private SessionDescription sd = null;
	private long sessionID = 0;
	private final String TAG = "DEBUG";
	private int port;

	final String CRLF = "\r\n";

	public RtspServer(InputStream is)
	{
		videoIn = is;
	}
	
	public void run()
	{
		int RTSPport = 5566;
		try {
			ServerSocket listenSocket = new ServerSocket(RTSPport);
			RTSPSocket = listenSocket.accept();
			
			Log.d("DEBUG","accept");
			listenSocket.close();

			ClientIPAddr = RTSPSocket.getInetAddress();

			state = READY;
			
			rs = new RtpSender(videoIn, ClientIPAddr);
			rs.setPort(6256);
			rs.send_start();
			Log.d(TAG,"recorder start");
			VideoServer.mRecorder.start();
			rs.start();
			Log.d("DEBUG","rtp start");
			
/*			
			//Set input and output stream filters:
			RTSPBufferedReader = new BufferedReader(new InputStreamReader(RTSPSocket.getInputStream()) );
			RTSPBufferedWriter = new BufferedWriter(new OutputStreamWriter(RTSPSocket.getOutputStream()) );

			int request_type;
			while(isRunning)
			{
				request_type = parse_RTSP_request(); // block
				Log.i(TAG, "parse end");
				send_RTSP_response(request_type);
				Log.i(TAG, "response end");
			}
*/
		} catch (Exception e) {
			// TODO Auto-generated catch block
			Log.d(TAG, e.toString());
		}
	}
	
	void finalized()
	{
		try {
			RTSPSocket.close();
			rs.finalized();
			rs = null;
		} catch (IOException e) {
			Log.e(TAG, e.toString());
		}
		this.stop();
	}

	int parse_RTSP_request()
	{
		int request_type = -1;
		try{
			//parse request line and extract the request_type:
			String RequestLine = RTSPBufferedReader.readLine();
			//System.out.println("RTSP Server - Received from Client:");
			//System.out.println(RequestLine);
			Log.d("DEBUG", RequestLine);
			StringTokenizer tokens = new StringTokenizer(RequestLine);
			String request_type_string = tokens.nextToken();

			//convert to request_type structure:
			if ((new String(request_type_string)).compareTo("OPTIONS") == 0)
				request_type = OPTIONS;
			else if ((new String(request_type_string)).compareTo("DESCRIBE") == 0)
				request_type = DESCRIBE;
			else if ((new String(request_type_string)).compareTo("SETUP") == 0)
				request_type = SETUP;
			else if ((new String(request_type_string)).compareTo("PLAY") == 0)
				request_type = PLAY;
			else if ((new String(request_type_string)).compareTo("PAUSE") == 0)
				request_type = PAUSE;
			else if ((new String(request_type_string)).compareTo("TEARDOWN") == 0)
				request_type = TEARDOWN;

			//parse the SeqNumLine and extract CSeq field
			String SeqNumLine = RTSPBufferedReader.readLine();
			//System.out.println(SeqNumLine);
			tokens = new StringTokenizer(SeqNumLine);
			tokens.nextToken();
			RTSPSeqNb = Integer.parseInt(tokens.nextToken());

			//read all of the request
			if(request_type == SETUP)
			{
				RequestLine = RTSPBufferedReader.readLine();
				RequestLine = RTSPBufferedReader.readLine();
				//RequestLine = RTSPBufferedReader.readLine();
				//RequestLine = RTSPBufferedReader.readLine();
				String[] strs = RequestLine.split("=");
				strs = strs[1].split("-");
				port = Integer.parseInt(strs[0]);
	
				//Log.d("yayayayaya","port = "+Integer.toString(port));
				
				//FileWriter fos = new FileWriter("/sdcard/debug.txt");
				//fos.write(Integer.toString(port));
				//fos.close();
				
				rs.setPort(port);
			}
			while((RequestLine = RTSPBufferedReader.readLine()).length()>0)
				Log.d(TAG, RequestLine);

		}
		catch(Exception ex)
		{
			//System.out.println("Exception caught: "+ex);
			//System.exit(0);
			Log.e(TAG, "parse:" + ex.toString());
			isRunning = false;
		}
		return(request_type);
	}

	private void send_RTSP_response(int request_type)
	{
		

		Log.v(TAG, "send start: " + request_type);
		if(request_type == -1)
		{
			return;
		}
		try{
			RTSPBufferedWriter.write("RTSP/1.0 200 OK"+CRLF);
			RTSPBufferedWriter.write("CSeq: "+RTSPSeqNb+CRLF);
			//RTSPBufferedWriter.write("Session: "+RTSP_ID+CRLF);
			
			//System.out.println("RTSP Server - Sent response to Client.");
			if(request_type == OPTIONS)
			{
				RTSPBufferedWriter.write("Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, OPTIONS"+CRLF);
				RTSPBufferedWriter.write(CRLF);
			}
			
			else if(request_type == DESCRIBE)
			{
				//Create SDP message				
				try {
					
					sd = new SessionDescription(
							SDPFactory.createVersion(),
							SDPFactory.createOrigin("simon", 0, VideoServer.getLocalIpAddress()),
							SDPFactory.createSessionName(),
							new TimeDescription()
							);
					
					Bandwith[] bw = new Bandwith[1];
					bw[0] = SDPFactory.createBandwith("AS", 80);
					sd.setBandwiths(bw);
					sd.setConnection(SDPFactory.createConnection(VideoServer.getLocalIpAddress()));
					sd.addAttribute(SDPFactory.createAttribute("control", "*"));
					//sd.addAttribute(SDPFactory.createAttribute("range", "npt=0-"));
					
					
					// media
					Media media = new Media("video", 5568, 1, "RTP/AVP", "96");
					MediaDescription md = new MediaDescription(media);
					md.addBandwith(SDPFactory.createBandwith("AS", 80));
					//md.addAttribute(SDPFactory.createAttribute("rtpmap", "96 MP4V-ES/90000"));
					//md.addAttribute(SDPFactory.createAttribute("rtpmap", "96 MPEG4-SP/90000"));
					md.addAttribute(SDPFactory.createAttribute("rtpmap", "96 H263-1998/90000"));
					md.addAttribute(SDPFactory.createAttribute("control", "*"));
					//md.addAttribute(SDPFactory.createAttribute("fmtp", "96 profile-level-id=1;config=000001B002000001B5090000010000000120008440FA285020F0A31F"));
					//md.addAttribute(SDPFactory.createAttribute("mpeg4-esid", "201"));
					//md.addAttribute(SDPFactory.createAttribute("cliprect", "0,0,176,144"));
					md.addAttribute(SDPFactory.createAttribute("framesize", "96 176-144"));
					md.addAttribute(SDPFactory.createAttribute("range", "npt=0-60"));
					sd.addMediaDescription(md);
				} catch (SDPException e) {
					Log.e(TAG, "==Sdp Exception==" + e.toString());
					e.printStackTrace();
				} catch (Exception e) {
					Log.e(TAG, "==Other Exception==" + e.toString());
					e.printStackTrace();
				}
				
				//RTSPBufferedWriter.write("Cache-Control: must-revalidate\r\n");
				RTSPBufferedWriter.write("Content-length: " + sd.toString().length() + CRLF);
				RTSPBufferedWriter.write("Content-Type: application/sdp" + CRLF);
				//RTSPBufferedWriter.write("x-Accept-Retransmit: our-retransmit\r\n");
				//RTSPBufferedWriter.write("x-Accept-Dynamic-Rate: 1\r\n");
				//RTSPBufferedWriter.write("Content-Base: rtsp://114.32.53.209:5566/sample_100kbit.mp4/\r\n");
				RTSPBufferedWriter.write(CRLF);
				RTSPBufferedWriter.write(sd.toString());
				sessionID = sd.getOrigin().getSessionID();
			}
			else if(request_type == SETUP)
			{
				RTSPBufferedWriter.write("Session: " + sessionID + CRLF);
				RTSPBufferedWriter.write("Transport: RTP/AVP;unicast;client_port="+port+"-"+(port+1)+";server_port=6256-6257" + CRLF);
				RTSPBufferedWriter.write(CRLF);
				
				VideoServer.mRecorder.start();
				Log.d("TIME","Media Start!!!!!!!");
				rs.start();
			}
			else if(request_type == PLAY)
			{
				state = PLAYING;
				RTSPBufferedWriter.write("Session: " + sessionID + CRLF);
				RTSPBufferedWriter.write("Range: npt=0.00000-" + CRLF);
				RTSPBufferedWriter.write("RTP-Info: url=rtsp://"+VideoServer.getLocalIpAddress()+"/sample_100kbit.mp4/*;seq=2;" + CRLF);
				RTSPBufferedWriter.write(CRLF);
			
				rs.send_start();
			}
			else if(request_type == PAUSE)
			{
				RTSPBufferedWriter.write(CRLF);
				RTSPBufferedWriter.flush();
				rs.send_stop();
			}
			else if(request_type == TEARDOWN)
			{
				RTSPBufferedWriter.write(CRLF);
				RTSPBufferedWriter.flush();
				rs.send_stop();
				this.finalized();
			}
			
			RTSPBufferedWriter.flush();
			Log.v("DEBUG", "send end");
		}
		catch(Exception ex)
		{
			System.out.println("Exception caught: "+ex);
			System.exit(0);
		}
	}
}